#include <condition_variable>
#include <mutex>
#include <queue>
#include <thread>
#include <iostream>

// 生产的总任务数量
constexpr int kItems = 10;

// 互斥锁，保护共享队列与 done 标志
std::mutex m;

// 条件变量，用于在队列为空时阻塞消费者，或唤醒等待的线程
std::condition_variable cv;

// 共享任务队列，生产者负责 push，消费者负责 pop
std::queue<int> buffer;

// 标记生产者是否全部完成，用于唤醒消费者并退出循环
bool done = false;

// 生产者线程函数
void producer() {
    for (int i = 0; i < kItems; ++i) {
        {
            // 上锁保护共享队列
            std::lock_guard<std::mutex> lg(m);
            buffer.push(i); // 推入新任务
        } // 离开作用域，自动解锁

        cv.notify_one(); // 通知一个可能正在等待的消费者
    }

    {
        // 所有任务生成完毕，设置完成标记
        std::lock_guard<std::mutex> lg(m);
        done = true;
    }
    cv.notify_one(); // 再次通知，唤醒可能等待的新任务的消费者
}

// 消费者线程函数
void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lk(m); // 使用 unique_lock 以便 wait 时解锁 / 锁定
        // 等待条件：队列非空，或者生产者已完成
        cv.wait(lk, [] { return !buffer.empty() || done; });

        if (!buffer.empty()) {
            int item = buffer.front(); // 取出队头元素
            buffer.pop();
            lk.unlock(); // 出临界区，减少锁定范围

            std::cout << "consume " << item << '\n';
        } else if (done) {
            // 队列为空且生产者结束 -> 消费者退出
            break;
        }
    }
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
}